﻿//-----------------------------------------------------------------------
// <copyright file="Program.cs" company="DylanBox">
// Copyright (c) DylanBox Corporation. All rights reserved.
// </copyright>
// <summary>
//  IAsyncResult result = caller.BeginInvoke(...);
//  result.IsCompleted();
// </summary>
// <reference>
//    http://www.dotnetscraps.com/dotnetscraps/post/Explaining-Delegates-in-C-Part-6-(Asynchronous-Callback-Way-3).aspx
// </reference>
// <author>Dylan</author>
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace EventAndDelegateDemo
{
    //The delegate must have the same signature as the method. In this case,
    //we will make it same as TortoiseMethod
    public delegate string TortoiseCaller(int seconds, out int threadId);

    public class TortoiseClass
    {
        // The method to be executed asynchronously.
        public string TortoiseMethod(int seconds, out int threadId)
        {
            Console.WriteLine("The slow method... executes...on thread {0}", Thread.CurrentThread.ManagedThreadId);
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(seconds / 5 * 1000);
                //Console.WriteLine("The async task is going on thread # {0}", Thread.CurrentThread.ManagedThreadId);
            }
            threadId = Thread.CurrentThread.ManagedThreadId;
            return String.Format("I worked in my sleep for {0} seconds", seconds.ToString());
        }
    }

    //Now, that we are done with the declaration part, let's proceed to
    //consume the classes and see it in action
    //The algorithm would be very simple...
    //         1. Call delegate's BeginInvoke
    //         2. Do some work on the main thread
    //         3. Keep polling using result's IsCompleted property
    //         4. Call EndInvoke which won't be a blocking call this time!
    public class TortoiseConsumer
    {
        static void Main()
        {
            //Instantiate a new TortoiseClass
            TortoiseClass tc = new TortoiseClass();
            //Let's create the delegate now
            TortoiseCaller caller = new TortoiseCaller(tc.TortoiseMethod);
            //The asynchronous method puts the thread id here
            int threadId;
            //Make the async call. Notice that this thread continues to run after making this call
            Console.WriteLine("Before making the Async call... Thread ID = {0}", Thread.CurrentThread.ManagedThreadId);
            IAsyncResult result = caller.BeginInvoke(25, out threadId, null, null);
            //After calling the method asynchronously, the main thread continues to work...
            Console.WriteLine("After making the Async call... Thread ID = {0}", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Start the polling...\nWaiting for the Tortoise method to complete...");
            //The IAsynResult interface uses IsCompleted property which you can use to figure out if the call is complete
            //Notice that this will be a  blocking call until the Async call completes.
            while (result.IsCompleted == false)
            {
                Console.Write(".");
                Thread.Sleep(500);
            }
            //Normally, EndInvoke would be a blocking call, but in this case... it won't be.
            //The reason is that we now know that the Async call is completed!
            string returnValue = caller.EndInvoke(out threadId, result);
            Console.WriteLine("\nThe call got executed on thread {0}", threadId);
            Console.WriteLine("The value returned was - {0}", returnValue);
        }
    }
}
